package com.jaya.budan.utils;

import android.os.Build;

import androidx.annotation.RequiresApi;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;

/**
 * <h1>日期解析、格式化、转换等操作</h1>
 * Created by woniu
 */
@RequiresApi(api = Build.VERSION_CODES.O)
public class LocalDateTimeUtil {

    // 日期默认格式
    public static final String DATE_FORMAT = "yyyy-MM-dd";

    // 日期时间默认格式
    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * <h2>获取当前系统时间</h2>
     * @return 当前系统时间
     * */
    public static LocalDateTime now(){
        return LocalDateTime.now();
    }

    /**
     * <h2>获取当前系统时间戳，单位：秒</h2>
     * @return 当前系统时间戳，单位：秒
     * */
    public static final long second() {
        return LocalDateTimeUtil.now().toEpochSecond(ZoneOffset.of("+8"));
    }

    /**
     * <h2>获取当前系统时间戳，单位：毫秒</h2>
     * @return 当前系统时间戳，单位：毫秒
     * */
    public static final long milliSecond() {
        return milliSecond(LocalDateTimeUtil.now());
    }

    public static final long milliSecond(LocalDateTime localDateTime){
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * <h2>格式化日期时间，LocalDateTime 转 String</h2>
     * @param localDateTime {@link LocalDateTime}
     * @return 日期时间字符串
     * */
    public static String format(LocalDateTime localDateTime) {
        return format(localDateTime,DATE_TIME_FORMAT);
    }

    /**
     * <h2>格式化日期时间，LocalDateTime 转 String</h2>
     * @param localDateTime {@link LocalDateTime}
     * @param format 日期时间格式
     * @return 日期时间字符串
     * */
    public static String format(LocalDateTime localDateTime, String format) {
        if (format == null || "".equals(format)) {
            format = DATE_TIME_FORMAT;
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format);
        return dtf.format(localDateTime);
    }

    /**
     * <h2>格式化时间戳，时间戳 转 LocalDateTime</h2>
     * @param milliSecond 时间戳，单位毫秒
     * @return 日期时间
     * */
    public static LocalDateTime format(Long milliSecond) {
        return LocalDateTime.ofEpochSecond(milliSecond/1000,0,ZoneOffset.ofHours(8));
    }

    /**
     * <h2>格式化日期时间，String 转 LocalDateTime</h2>
     * @param dateTimeStr 日期时间字符串
     * @return 日期时间
     * */
    public static LocalDateTime parse(String dateTimeStr) {
        return parse(dateTimeStr,DATE_TIME_FORMAT);
    }

    /**
     * <h2>格式化日期时间，String 转 LocalDateTime</h2>
     * @param dateTimeStr 日期时间字符串
     * @param format 日期时间格式
     * @return 日期时间
     * */
    public static LocalDateTime parse(String dateTimeStr, String format) {
        if (format == null || "".equals(format)) {
            format = DATE_TIME_FORMAT;
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(dateTimeStr,dtf);
    }

    /**
     * <h2>日期偏移,根据field不同加不同值（偏移会修改传入的对象）</h2>
     * @param localDateTime   {@link LocalDateTime}
     * @param number 偏移量，正数为向后偏移，负数为向前偏移
     * @param offsetUnit  偏移单位，见{@link ChronoField} 和 {@link ChronoUnit}，不能为 null
     * @return 偏移后的日期时间
     * @see # YEARS-MONTHS-DAYS HOURS:MINUTES:SECONDS
     */
    public static LocalDateTime offset(LocalDateTime localDateTime, long number, TemporalUnit offsetUnit) {
        if (null == localDateTime) {
            return null;
        }

        return localDateTime.plus(number, offsetUnit);
    }

    /**
     * <h2>日期偏移,根据field不同加不同值（偏移会修改传入的对象）</h2>
     * @param localDateTime   {@link LocalDateTime}
     * @param number 偏移量，正数为向后偏移，负数为向前偏移
     * @return 偏移后的日期时间
     * @see # YEARS-MONTHS-DAYS HOURS:MINUTES:SECONDS
     */
    public static LocalDateTime offsetSeconds(LocalDateTime localDateTime, long number) {
        return offset(localDateTime, number, ChronoUnit.SECONDS);
    }

    /**
     * <h2>获取两个日期的差，如果结束时间早于开始时间，获取结果为负</h2>
     * 返回结果为{@link Duration}对象，通过调用 toXXX 方法返回相差单位
     * @param startLocalDateTime 开始时间（包含）
     * @param endLocalDateTime   结束时间（不包含）
     * @return 时间差 {@link Duration}对象
     */
    public static Duration between(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        return Duration.between(startLocalDateTime, endLocalDateTime);
    }

    /**
     * <h2>获取两个日期的差，如果结束时间早于开始时间，获取结果为负</h2>
     * 返回结果为时间差的 long 值
     * @param startLocalDateTime 开始时间（包括）
     * @param endLocalDateTime   结束时间（不包括）
     * @return 时间差，单位：秒
     */
    public static long betweenSeconds(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime) {
        return between(startLocalDateTime, endLocalDateTime, ChronoUnit.SECONDS);
    }

    /**
     * <h2>获取两个日期的差，如果结束时间早于开始时间，获取结果为负</h2>
     * 返回结果为时间差的 long 值
     * @param startLocalDateTime 开始时间（包括）
     * @param endLocalDateTime   结束时间（不包括）
     * @param chronoUnit         时间差单位
     * @return 时间差
     */
    public static long between(LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime, ChronoUnit chronoUnit) {
        return chronoUnit.between(startLocalDateTime, endLocalDateTime);
    }

    /**
     * <h2>判断指定日期是否在时间范围内</h2>
     * @param localDateTime 指定日期
     * @param startLocalDateTime 开始时间
     * @param endLocalDateTime 结束时间
     * @return true 是，false 否
     * */
    public static boolean contains(LocalDateTime localDateTime, LocalDateTime startLocalDateTime, LocalDateTime endLocalDateTime){
        if(localDateTime.isAfter(startLocalDateTime) && localDateTime.isBefore(endLocalDateTime)){
            return true;
        }
        return false;
    }

    /**
     * <h2>获取指定日期是周几</h2>
     * @param localDateTime 日期
     * @return 周几 1-7 表示 周一至周七
     * */
    public static int week(LocalDateTime localDateTime){
        return localDateTime.getDayOfWeek().getValue();
    }

    /**
     * <h2>周几数字转中文</h2>
     * @param week 周几数字
     * @return 周几中文
     * */
    public static String weekFormat(Integer week){
        String[] weekStr = {"","周一","周二","周三","周四","周五","周六","周日"};
        return weekStr[week];
    }

    public static void main(String[] args) {
        LocalDateTime localDateTime = LocalDateTimeUtil.now();
        System.out.println(localDateTime);
        String dateTimeStr = format(localDateTime);
        System.out.println(dateTimeStr);
        System.out.println(second());
        System.out.println(milliSecond());
        System.out.println(parse(dateTimeStr));
        System.out.println(format(milliSecond()));
        System.out.println(offset(localDateTime,1, ChronoUnit.YEARS));
        System.out.println(offset(localDateTime,1, ChronoUnit.MONTHS));
        System.out.println(offset(localDateTime,1, ChronoUnit.DAYS));
        System.out.println(offset(localDateTime,1, ChronoUnit.HOURS));
        System.out.println(offset(localDateTime,1, ChronoUnit.MINUTES));
        System.out.println(offset(localDateTime,1, ChronoUnit.SECONDS));
        LocalDateTime endLocalDateTime = offset(localDateTime,1, ChronoUnit.HOURS);
        Duration duration = between(localDateTime,endLocalDateTime);
        System.out.println(duration.toHours());
        System.out.println(betweenSeconds(localDateTime,endLocalDateTime));
        System.out.println(between(localDateTime,endLocalDateTime,ChronoUnit.YEARS));
        System.out.println("周" + week(localDateTime));
        System.out.println(weekFormat(week(localDateTime)));
        System.out.println(contains(localDateTime,offset(localDateTime,-1, ChronoUnit.SECONDS),offset(localDateTime,1, ChronoUnit.SECONDS)));
    }
}
